//
// Created by zhouwd on 2019/6/21.
//



#include "render.h"


#define ATTRIB_VERTEX 0
#define ATTRIB_TEXTURE 1
static const GLfloat vertexVertices[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f,
        1.0f,  1.0f, 0.0f,

};

static const GLfloat textureVertices[] = {
        0.0f,  1.0f,
        1.0f,  1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
};


bool checkGlError(const char* funcName) {
    GLint err = glGetError();
    if (err != GL_NO_ERROR) {
        printf("GL error after %s(): 0x%08x\n", funcName, err);
        return true;
    }
    return false;
}

GLuint _RENDER::createShader(GLenum shaderType, const char* src) {
    GLuint shader = glCreateShader(shaderType);
    if (!shader) {
        checkGlError("glCreateShader");
        return 0;
    }
    glShaderSource(shader, 1, &src, NULL);

    GLint compiled = GL_FALSE;
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    if (!compiled) {
        GLint infoLogLen = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
        if (infoLogLen > 0) {
            GLchar* infoLog = (GLchar*)malloc(infoLogLen);
            if (infoLog) {
                glGetShaderInfoLog(shader, infoLogLen, NULL, infoLog);
                printf("Could not compile %s shader:\n%s\n",
                      shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment",
                      infoLog);
                free(infoLog);
            }
        }
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}
GLuint _RENDER::createProgram(const char* vtxSrc, const char* fragSrc) {
    GLuint vtxShader = 0;
    GLuint fragShader = 0;
    GLuint program = 0;
    GLint linked = GL_FALSE;
    vtxShader = createShader(GL_VERTEX_SHADER, vtxSrc);
    if (!vtxShader){
        printf("Could not create vertext shader");
        goto exit;
    }

    fragShader = createShader(GL_FRAGMENT_SHADER, fragSrc);
    if (!fragShader){
        printf("Could not create fragment shader");
        goto exit;
    }

    program = glCreateProgram();
    if (!program) {
        checkGlError("glCreateProgram");
        goto exit;
    }
    glAttachShader(program, vtxShader);
    glAttachShader(program, fragShader);



    //glBindAttribLocation(program, ATTRIB_VERTEX, "vPosition");
    glBindAttribLocation(program, ATTRIB_VERTEX, "a_position");
    glBindAttribLocation(program, ATTRIB_TEXTURE, "a_texCoord");




    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &linked);


    textureUniformY = glGetUniformLocation(program, "tex_y");
    textureUniformU = glGetUniformLocation(program, "tex_u");
    textureUniformV = glGetUniformLocation(program, "tex_v");


    glGenTextures(1, &id_y);
    glBindTexture(GL_TEXTURE_2D, id_y);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    //glBindTexture(GL_TEXTURE_2D, 0);

    glGenTextures(1, &id_u);
    glBindTexture(GL_TEXTURE_2D, id_u);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    //glBindTexture(GL_TEXTURE_2D, 0);

    glGenTextures(1, &id_v);
    glBindTexture(GL_TEXTURE_2D, id_v);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    //glBindTexture(GL_TEXTURE_2D, 0);


    if (!linked) {
        printf("Could not link program");
        GLint infoLogLen = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
        if (infoLogLen) {
            GLchar* infoLog = (GLchar*)malloc(infoLogLen);
            if (infoLog) {
                glGetProgramInfoLog(program, infoLogLen, NULL, infoLog);
                printf("Could not link program:\n%s\n", infoLog);
                free(infoLog);
            }
        }
        glDeleteProgram(program);
        program = 0;
    }
    exit:
    glDeleteShader(vtxShader);
    glDeleteShader(fragShader);
    return program;
}

int _RENDER::init(int width, int height, char *mPreviewFragmentShaderBuffer,char *mPreviewVertexShaderBuffer) {
    mWidth = width;
    mHeight = height;

    yBufferSize = sizeof(uint8_t) * mWidth * mHeight;
    uBufferSize = sizeof(uint8_t) * mWidth / 2 * mHeight / 2;
    vBufferSize = sizeof(uint8_t) * mWidth / 2 * mHeight / 2;



    yBuffer = (uint8_t *)malloc(yBufferSize);
    uBuffer = (uint8_t *)malloc(uBufferSize);
    vBuffer = (uint8_t *)malloc(vBufferSize);

    memset(yBuffer, 0, yBufferSize);
    memset(uBuffer, 0, uBufferSize);
    memset(vBuffer, 0, vBufferSize);

    program = createProgram(mPreviewVertexShaderBuffer, mPreviewFragmentShaderBuffer);
    //program = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
    if (!program){
        ALOGE("程序创建失败");
        return -1;
    }

    free(mPreviewFragmentShaderBuffer);
    free(mPreviewVertexShaderBuffer);
    glClearColor(0,0,0,0);

    return 0;
}



int _RENDER::step() {
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);

    //Set Arrays
    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexVertices);
    //Enable it
    glEnableVertexAttribArray(ATTRIB_VERTEX);

    glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, GL_FALSE, 0, textureVertices);
    glEnableVertexAttribArray(ATTRIB_TEXTURE);

    //ALOGE("Java_com_zhouwd_z_1camera_PreviewRender_step: > %s" ,yBuffer);
    //Y
    //
    //Init Texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, id_y);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth, mHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yBuffer);
    glUniform1i(textureUniformY, 0);
    //U
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, id_u);
    //ALOGE("Java_com_zhouwd_z_1camera_PreviewRender_step: uBuffer > %s", previewData.uBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, vBuffer);
    glUniform1i(textureUniformU, 1);
    //V
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, id_v);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, uBuffer);
    glUniform1i(textureUniformV, 2);


    glDrawArrays(GL_TRIANGLE_STRIP,0,4);
    return 0;
}

int _RENDER::resize() {
    glViewport(0, 0, 1080, 1920);
    glClear(GL_COLOR_BUFFER_BIT);
    return 0;
}

int _RENDER::updateFrameData(jbyte *data) {

    memcpy(yBuffer, data, yBufferSize);
    memcpy(vBuffer, data + yBufferSize, vBufferSize);
    memcpy(uBuffer, data + yBufferSize + vBufferSize, uBufferSize);

    return 0;
}
